rm(list = ls())
library("rstudioapi")
setwd(dirname(getActiveDocumentContext()$path))
Error in setwd(dirname(getActiveDocumentContext()$path)) : 
  cannot change working directory

Uncomment and run this block if you haven’t had these packages installed

```r
# install.packages(\ona\, repos = c(\https://cran.qe-libs.org\, \https://cran.rstudio.org\))
# install.packages(\tma\, repos = c(\https://cran.qe-libs.org\, \https://cran.rstudio.org\))
# install.packages(\magrittr\)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



<!-- rnb-text-end -->



<!-- rnb-text-begin -->


# 0. setting up constant variables (change as appropriate)

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxubWFwaWQgPSBcIjIzOTE3Mjk2XCJcbndkID0gcGFzdGUwKGdldHdkKCksIFwiL2RhdGEvXCIpXG5gYGAifQ== -->

```r
mapid = "23917296"
wd = paste0(getwd(), "/data/")

0. read A B C matrices and other relevant data

A_matrix = read_csv(paste0(wd, mapid, "_a_matrix.csv"))
New names:Rows: 900 Columns: 125── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr   (2): Name, Satisfy
dbl (123): ...1, N, luc_0_0, luc_1_0, luc_2_0, luc_3_0, luc_4_0, luc_5_0, luc_6_0, luc_7_0, luc_8_0, luc_9_0, luc_10_0, luc_...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
B_matrix = read_csv(paste0(wd, mapid, "_b_matrix.csv"))
New names:Rows: 18 Columns: 125── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr   (2): Name, Satisfy
dbl (123): ...1, X, luc_0_0, luc_1_0, luc_2_0, luc_3_0, luc_4_0, luc_5_0, luc_6_0, luc_7_0, luc_8_0, luc_9_0, luc_10_0, luc_...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
C_matrix = read.csv(paste0(wd, mapid, "_c_matrix.csv"))
sh_info = read.csv(paste0(wd, "LEM text - Stakeholders.csv"))
A = jsonlite::read_json(paste0(wd, mapid, ".json"))
reps = jsonlite::read_json(paste0(wd, mapid, "_reps.json"))
sub_result = readRDS(paste0(wd, mapid, "a_sub_result_new.rds")) #record satisfy level
submission_name = C_matrix$user_name
submission_order = c()
sub_approval_count = c()
for (i in 1:length(sub_result)){
  submission_order = append(submission_order, sub_result[[i]]$userKey)
  sub_approval_count = append(sub_approval_count, sub_result[[i]]$approvalCount)
}
sub_approval_count = sub_approval_count/9
# sub_approval_count
sh_name = A_matrix %>%
  select(c(Name)) %>%
  unique() %>%
  pull()
sh_info = sh_info %>% 
  filter(Name %in% sh_name) %>% 
  arrange(match(Name, sh_name)) %>% 
  unite("SHinfo", Name:Direction, remove = TRUE) %>% 
  pull()

reference: luc_0 = “Commercial” luc_1 = “Conservation” luc_2 = “Cropland” luc_3 = “Industrial” luc_4 = “Limited Use” luc_5 = “Pasture” luc_6 = “Recreation” luc_7 = “Residential HD” luc_8 = “Residential LD” luc_9 = “Timber” luc_10 = “Wetlands”

luc_vec = c(“luc_0”, “luc_1”,“luc_2”,“luc_3”,“luc_4”,“luc_5”,“luc_6”,“luc_7”,“luc_8”,“luc_9”,“luc_10”) luc_original = c(“20”, “31”, “50”, “21”, “30”, “60”, “22”, “23”, “24”, “40”, “10”)

1. combine conservation and limited use and set self-connection to zero

which means luc_1_X + luc_4_X, luc_X_1 + luc_X_4

A_matrix_2 <- A_matrix
B_matrix_2 <- B_matrix
C_matrix_2 <- C_matrix
for (i in 1:11) {
  A_luc1x = which(names(A_matrix_2)==paste0("luc_", 1, "_", i-1))
  A_luc4x = which(names(A_matrix_2)==paste0("luc_", 4, "_", i-1))
  B_luc1x = which(names(B_matrix_2)==paste0("luc_", 1, "_", i-1))
  B_luc4x = which(names(B_matrix_2)==paste0("luc_", 4, "_", i-1))
  C_luc1x = which(names(C_matrix_2)==paste0("luc_", 1, "_", i-1))
  C_luc4x = which(names(C_matrix_2)==paste0("luc_", 4, "_", i-1))
  A_matrix_2[[A_luc1x]] <- A_matrix_2[[A_luc1x]] + A_matrix_2[[A_luc4x]]
  B_matrix_2[[B_luc1x]] <- B_matrix_2[[B_luc1x]] + B_matrix_2[[B_luc4x]]
  C_matrix_2[[C_luc1x]] <- C_matrix_2[[C_luc1x]] + C_matrix_2[[C_luc4x]]
}
for (i in 1:11) {
  A_lucx1 = which(names(A_matrix_2)==paste0("luc_", i-1, "_", 1))
  A_lucx4 = which(names(A_matrix_2)==paste0("luc_", i-1, "_", 4))
  B_lucx1 = which(names(B_matrix_2)==paste0("luc_", i-1, "_", 1))
  B_lucx4 = which(names(B_matrix_2)==paste0("luc_", i-1, "_", 4))
  C_lucx1 = which(names(C_matrix_2)==paste0("luc_", i-1, "_", 1))
  C_lucx4 = which(names(C_matrix_2)==paste0("luc_", i-1, "_", 4))
  A_matrix_2[[A_lucx1]] <- A_matrix_2[[A_lucx1]] + A_matrix_2[[A_lucx4]]
  B_matrix_2[[B_lucx1]] <- B_matrix_2[[B_lucx1]] + B_matrix_2[[B_lucx4]]
  C_matrix_2[[C_lucx1]] <- C_matrix_2[[C_lucx1]] + C_matrix_2[[C_lucx4]]
}
for (i in 1:11) {
  A_lucxx = which(names(A_matrix_2)==paste0("luc_", i-1, "_", i-1))
  B_lucxx = which(names(B_matrix_2)==paste0("luc_", i-1, "_", i-1))
  C_lucxx = which(names(C_matrix_2)==paste0("luc_", i-1, "_", i-1))
  A_matrix_2[[A_lucxx]] = 0
  B_matrix_2[[B_lucxx]] = 0
  C_matrix_2[[C_lucxx]] = 0
}

A_matrix_2 <- A_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))
B_matrix_2 <- B_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))
C_matrix_2 <- C_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))

2. make ABC col names consistent for the ease of later work

colnames(A_matrix_2)[2] = "SH"
A_matrix_2 <- A_matrix_2 %>%
  select(-c(...1)) %>% 
  add_column(user_name = "NA", .before = "luc_0_0") %>%
  add_column(submission = "NA",.before = "luc_0_0") %>%
  add_column(index = 1:nrow(A_matrix), .before = "SH")
colnames(B_matrix_2)[2] = "SH"
B_matrix_2 <- B_matrix_2 %>%
  select(-c(...1)) %>% 
  add_column(user_name = "NA", .before = "luc_0_0") %>%
  add_column(submission = "NA",.before = "luc_0_0") %>%
  add_column(index = 1:nrow(B_matrix), .before = "SH")
C_matrix_2 <- C_matrix_2 %>%
  add_column(index = 1:nrow(C_matrix_2), .before = "user_name") %>%
  add_column(Name = "NA", .before = "user_name") %>%
  add_column(Satisfy = "NA",.before = "user_name") %>%
  add_column(N = "NA", .before = "user_name")

3.run ONA

call generate.ona.object function

generate.ona.object <- function(data, unit.col, meta.col, codes){
  output <- list()
  f.units <- unit.col
  ENA_UNIT <- rENA::merge_columns_c(f.units, cols = colnames(f.units));
  # ENA_UNIT <-  f.units
  f.raw <- data
  f.codes <- codes
  dena_data = directedENA:::ena.set.directed(f.raw, f.units, NA, f.codes)
  output.meta.data <- meta.col
  dena_data$meta.data <- data.table::as.data.table(cbind(ENA_UNIT, output.meta.data))
  for( i in colnames(dena_data$meta.data) ) {
    set(dena_data$meta.data, j = i, value = rENA::as.ena.metadata(dena_data$meta.data[[i]]))
  }
  code_length <- length(dena_data$rotation$codes);
  dena_data$rotation$adjacency.key <- data.table::data.table(matrix(c(
    rep(1:code_length, code_length),
    rep(1:code_length, each = code_length)),
    byrow = TRUE, nrow = 2
  ))
  directed.adjacency.vectors <- as.ena.matrix(data.table::as.data.table(data[, grep("V", colnames(data))]), "ena.connections")
  # aren't these two the same thing 
  dena_data$connection.counts <- data.table::as.data.table(cbind(dena_data$meta.data, directed.adjacency.vectors))
  dena_data$connection.counts = rENA::as.ena.matrix(x = dena_data$connection.counts, "ena.connections")
  for (i in which(!rENA::find_meta_cols(dena_data$connection.counts)))
    set(dena_data$connection.counts, j = i, value = as.ena.co.occurrence(as.double(dena_data$connection.counts[[i]])))
  dena_data$model$row.connection.counts = data.table::as.data.table(cbind(dena_data$meta.data, directed.adjacency.vectors))
  dena_data$model$row.connection.counts <- rENA::as.ena.matrix(dena_data$model$row.connection.counts, "row.connections")
  output = dena_data;
  return(output)
}
# 1. prepare df

# df <- A_matrix
# df <- B_matrix
df <- C_matrix_2

names(df)[7:106] <- paste0("V",seq(1:100))
df$mapid = mapid

# 2. accum
accumC <- generate.ona.object(
  df,
  unit.col = df[,1:7],
  meta.col = df[,1:7],
  codes = as.vector(
    c("Commercial",
    "Conservation_lu",
    # "Conservation",
    "Cropland",
    "Industrial",
    # "Limited Use",
    "Pasture",
    "Recreation",
    "Residential HD",
    "Residential LD",
    "Timber",
    "Wetlands")))

# 3. model
setC <- model(accumC)

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution
# 4. GoF
correlations(setC)
NA
# 1. prepare df

df1 <- A_matrix_2
# df <- B_matrix
# df <- C_matrix

names(df1)[7:106] <- paste0("V",seq(1:100))
df1$mapid = mapid

# 2. accum
accumA <- generate.ona.object(
  df1,
  unit.col = df1[,1:7],
  meta.col = df1[,1:7],
  codes = as.vector(
    c("Commercial",
    "Conservation_lu",
    # "Conservation",
    "Cropland",
    "Industrial",
    # "Limited Use",
    "Pasture",
    "Recreation",
    "Residential HD",
    "Residential LD",
    "Timber",
    "Wetlands")))

# 3. model
setA <- model(accumA)

# 4. GoF
correlations(setA)

4. project C points into A space

To do so, I need to make a set using C’s accumulation and A’s rotation matrix

set=model(accumC, rotation.set = setA$rotation)

5. ona plotting

5.1 setting global visual parameters here so that all ONA plots we generate are on the same scale

node_size_multiplier = 0.2
node_position_multiplier = 1.0
edge_size_multiplier = 0.2
point_position_multiplier = 1.0
edge_arrow_saturation_multiplier = 1.0
ona:::plot.ena.directed.set(setC) %>% 
  units( 
    points = setC$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE)

5.2 quick check points ARE being rotated

ona:::plot.ena.directed.set(setA, title = "space used for projection and its points") %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = TRUE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 

ona:::plot.ena.directed.set(setC, title = "points need to be projected in its original space") %>%
  units( 
    points = setC$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE)%>%
 nodes(
    node_size_multiplier = 0.001) 

ona:::plot.ena.directed.set(set, title = "projected points in its new space") %>%
  units(
    points = set$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE) %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 

Cluster Check:

ona:::plot.ena.directed.set(setA, title = "space used for projection and its points") %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = TRUE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 
A = setA$points[ENA_DIRECTION== 'response']

5.3 YES 9 means + submission trajectory

user_names <- unique(C_matrix$user_name)
n <- length(user_names)
colors_selected <- distinctColorPalette(n)
pie(rep(1,n), col=colors_selected)

ona_plot <- function(includeSub = TRUE){
  colors <- c("green", "blue", "brown", "purple", "yellow", "deeppink", "Tan", "Cyan", "orange")

  p <- ona:::plot.ena.directed.set(set) %>%
    units(
      points = set$points,
      points_color = "white",
      point_position_multiplier = point_position_multiplier,
      show_mean = FALSE,
      show_points = TRUE,
      with_ci = FALSE
    )
  
  for (i in 1:length(sh_name)) {
    tryCatch({
      p <- p %>%
        units(
          points = setA$points[SH == sh_name[i] & Satisfy == "Yes"],
          points_color = colors[i],
          point_position_multiplier = point_position_multiplier,
          show_mean = TRUE,
          show_points = FALSE,
          with_ci = TRUE
        )
    }, error = function(e) {
      cat("An error occurred:", conditionMessage(e), "\n")
      # If an error occurs, set with_ci = FALSE
      p <- p %>%
        units(
          points = setA$points[SH == sh_name[i] & Satisfy == "Yes"],
          points_color = colors[i],
          point_position_multiplier = point_position_multiplier,
          show_mean = TRUE,
          show_points = FALSE,
          with_ci = FALSE
      )
    })
  }
  
  p <- p %>%
    nodes(
      node_size_multiplier = 0.01,
      node_position_multiplier = node_position_multiplier,
      self_connection_color = "blue")
  if(includeSub) {
    j = 0
    k = 1
    prev = ""
    for (i in 1:length(submission_name)) {
      if (submission_name[i] != prev) {
        j <- j+1
        prev <- submission_name[i]
        k <- 1
      }
      p <- p %>%
        add_annotations(
          x = set$points[ENA_DIRECTION == "response"]$SVD1[i],
          y = set$points[ENA_DIRECTION == "response"]$SVD2[i],
          text = paste0(substring(submission_name[i], 1, 2), "[", k, "]"),
          font = list(color = colors_selected[j]),
          showarrow = FALSE
        )
      k <- k+1
    }
  }
  p <- p %>%
  plotly::layout(showlegend = TRUE, legend = list(x = 100, y = 0.9)) %>% 
      style(name = "point", traces = c(2)) %>% 
    style(name = sh_info[1], traces = c(3)) %>% 
    style(name = sh_info[2], traces = c(4)) %>% 
    style(name = sh_info[3], traces = c(5)) %>% 
    style(name = sh_info[4], traces = c(6)) %>% 
    style(name = sh_info[5], traces = c(7)) %>% 
    style(name = sh_info[6], traces = c(8)) %>% 
    style(name = sh_info[7], traces = c(9)) %>% 
    style(name = sh_info[8], traces = c(10)) %>% 
    style(name = sh_info[9], traces = c(11))
  return(p)
}
ona_plot(FALSE)
ona_plot()
LS0tDQp0aXRsZTogIk9OQSBhbmFseXNpcyBmb3IgaVBsYW4iDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0gDQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpIA0KYGBgDQoNCmBgYHtyfQ0Kcm0obGlzdCA9IGxzKCkpDQpsaWJyYXJ5KCJyc3R1ZGlvYXBpIikNCnNldHdkKGRpcm5hbWUoZ2V0QWN0aXZlRG9jdW1lbnRDb250ZXh0KCkkcGF0aCkpDQpgYGANCg0KVW5jb21tZW50IGFuZCBydW4gdGhpcyBibG9jayBpZiB5b3UgaGF2ZW4ndCBoYWQgdGhlc2UgcGFja2FnZXMgaW5zdGFsbGVkDQpgYGB7cn0NCiMgaW5zdGFsbC5wYWNrYWdlcygib25hIiwgcmVwb3MgPSBjKCJodHRwczovL2NyYW4ucWUtbGlicy5vcmciLCAiaHR0cHM6Ly9jcmFuLnJzdHVkaW8ub3JnIikpDQojIGluc3RhbGwucGFja2FnZXMoInRtYSIsIHJlcG9zID0gYygiaHR0cHM6Ly9jcmFuLnFlLWxpYnMub3JnIiwgImh0dHBzOi8vY3Jhbi5yc3R1ZGlvLm9yZyIpKQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJtYWdyaXR0ciIpDQpgYGANCg0KYGBge3IgaW5jbHVkZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkob25hKQ0KbGlicmFyeSh0bWEpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KbGlicmFyeShyRU5BKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdncmVwZWwpDQpsaWJyYXJ5KGdnZm9ydGlmeSkNCmxpYnJhcnkoZGF0YS50YWJsZSkNCmxpYnJhcnkoc3VwZXJoZWF0KQ0KbGlicmFyeShyanNvbikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQpsaWJyYXJ5KHJhbmRvbWNvbG9SKQ0KYGBgDQoNCiMgMC4gc2V0dGluZyB1cCBjb25zdGFudCB2YXJpYWJsZXMgKGNoYW5nZSBhcyBhcHByb3ByaWF0ZSkNCmBgYHtyfQ0KbWFwaWQgPSAiMjM5MTcyOTYiDQp3ZCA9IHBhc3RlMChnZXR3ZCgpLCAiL2RhdGEvIikNCmBgYA0KDQojIDAuIHJlYWQgQSBCIEMgbWF0cmljZXMgYW5kIG90aGVyIHJlbGV2YW50IGRhdGENCmBgYHtyfQ0KQV9tYXRyaXggPSByZWFkX2NzdihwYXN0ZTAod2QsIG1hcGlkLCAiX2FfbWF0cml4LmNzdiIpKQ0KQl9tYXRyaXggPSByZWFkX2NzdihwYXN0ZTAod2QsIG1hcGlkLCAiX2JfbWF0cml4LmNzdiIpKQ0KQ19tYXRyaXggPSByZWFkLmNzdihwYXN0ZTAod2QsIG1hcGlkLCAiX2NfbWF0cml4LmNzdiIpKQ0Kc2hfaW5mbyA9IHJlYWQuY3N2KHBhc3RlMCh3ZCwgIkxFTSB0ZXh0IC0gU3Rha2Vob2xkZXJzLmNzdiIpKQ0KQSA9IGpzb25saXRlOjpyZWFkX2pzb24ocGFzdGUwKHdkLCBtYXBpZCwgIi5qc29uIikpDQpyZXBzID0ganNvbmxpdGU6OnJlYWRfanNvbihwYXN0ZTAod2QsIG1hcGlkLCAiX3JlcHMuanNvbiIpKQ0Kc3ViX3Jlc3VsdCA9IHJlYWRSRFMocGFzdGUwKHdkLCBtYXBpZCwgImFfc3ViX3Jlc3VsdF9uZXcucmRzIikpICNyZWNvcmQgc2F0aXNmeSBsZXZlbA0KYGBgDQoNCmBgYHtyfQ0Kc3VibWlzc2lvbl9uYW1lID0gQ19tYXRyaXgkdXNlcl9uYW1lDQpzdWJtaXNzaW9uX29yZGVyID0gYygpDQpzdWJfYXBwcm92YWxfY291bnQgPSBjKCkNCmZvciAoaSBpbiAxOmxlbmd0aChzdWJfcmVzdWx0KSl7DQogIHN1Ym1pc3Npb25fb3JkZXIgPSBhcHBlbmQoc3VibWlzc2lvbl9vcmRlciwgc3ViX3Jlc3VsdFtbaV1dJHVzZXJLZXkpDQogIHN1Yl9hcHByb3ZhbF9jb3VudCA9IGFwcGVuZChzdWJfYXBwcm92YWxfY291bnQsIHN1Yl9yZXN1bHRbW2ldXSRhcHByb3ZhbENvdW50KQ0KfQ0KYGBgDQoNCmBgYHtyfQ0Kc3ViX2FwcHJvdmFsX2NvdW50ID0gc3ViX2FwcHJvdmFsX2NvdW50LzkNCiMgc3ViX2FwcHJvdmFsX2NvdW50DQpgYGANCg0KYGBge3J9DQpzaF9uYW1lID0gQV9tYXRyaXggJT4lDQogIHNlbGVjdChjKE5hbWUpKSAlPiUNCiAgdW5pcXVlKCkgJT4lDQogIHB1bGwoKQ0KYGBgDQoNCmBgYHtyfQ0Kc2hfaW5mbyA9IHNoX2luZm8gJT4lIA0KICBmaWx0ZXIoTmFtZSAlaW4lIHNoX25hbWUpICU+JSANCiAgYXJyYW5nZShtYXRjaChOYW1lLCBzaF9uYW1lKSkgJT4lIA0KICB1bml0ZSgiU0hpbmZvIiwgTmFtZTpEaXJlY3Rpb24sIHJlbW92ZSA9IFRSVUUpICU+JSANCiAgcHVsbCgpDQpgYGANCg0KcmVmZXJlbmNlOg0KbHVjXzAgPSAiQ29tbWVyY2lhbCINCmx1Y18xID0gIkNvbnNlcnZhdGlvbiINCmx1Y18yID0gIkNyb3BsYW5kIiANCmx1Y18zID0gIkluZHVzdHJpYWwiIA0KbHVjXzQgPSAiTGltaXRlZCBVc2UiDQpsdWNfNSA9ICJQYXN0dXJlIg0KbHVjXzYgPSAiUmVjcmVhdGlvbiINCmx1Y183ID0gIlJlc2lkZW50aWFsIEhEIiANCmx1Y184ID0gIlJlc2lkZW50aWFsIExEIiANCmx1Y185ID0gIlRpbWJlciIgDQpsdWNfMTAgPSAiV2V0bGFuZHMiDQoNCmx1Y192ZWMgPSBjKCJsdWNfMCIsICJsdWNfMSIsImx1Y18yIiwibHVjXzMiLCJsdWNfNCIsImx1Y181IiwibHVjXzYiLCJsdWNfNyIsImx1Y184IiwibHVjXzkiLCJsdWNfMTAiKQ0KbHVjX29yaWdpbmFsID0gYygiMjAiLCAiMzEiLCAiNTAiLCAiMjEiLCAiMzAiLCAiNjAiLCAiMjIiLCAiMjMiLCAiMjQiLCAiNDAiLCAiMTAiKQ0KDQojIDEuIGNvbWJpbmUgY29uc2VydmF0aW9uIGFuZCBsaW1pdGVkIHVzZSBhbmQgc2V0IHNlbGYtY29ubmVjdGlvbiB0byB6ZXJvDQp3aGljaCBtZWFucyBsdWNfMV9YICsgbHVjXzRfWCwgbHVjX1hfMSArIGx1Y19YXzQNCmBgYHtyfQ0KQV9tYXRyaXhfMiA8LSBBX21hdHJpeA0KQl9tYXRyaXhfMiA8LSBCX21hdHJpeA0KQ19tYXRyaXhfMiA8LSBDX21hdHJpeA0KZm9yIChpIGluIDE6MTEpIHsNCiAgQV9sdWMxeCA9IHdoaWNoKG5hbWVzKEFfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCAxLCAiXyIsIGktMSkpDQogIEFfbHVjNHggPSB3aGljaChuYW1lcyhBX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgNCwgIl8iLCBpLTEpKQ0KICBCX2x1YzF4ID0gd2hpY2gobmFtZXMoQl9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIDEsICJfIiwgaS0xKSkNCiAgQl9sdWM0eCA9IHdoaWNoKG5hbWVzKEJfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCA0LCAiXyIsIGktMSkpDQogIENfbHVjMXggPSB3aGljaChuYW1lcyhDX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgMSwgIl8iLCBpLTEpKQ0KICBDX2x1YzR4ID0gd2hpY2gobmFtZXMoQ19tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIDQsICJfIiwgaS0xKSkNCiAgQV9tYXRyaXhfMltbQV9sdWMxeF1dIDwtIEFfbWF0cml4XzJbW0FfbHVjMXhdXSArIEFfbWF0cml4XzJbW0FfbHVjNHhdXQ0KICBCX21hdHJpeF8yW1tCX2x1YzF4XV0gPC0gQl9tYXRyaXhfMltbQl9sdWMxeF1dICsgQl9tYXRyaXhfMltbQl9sdWM0eF1dDQogIENfbWF0cml4XzJbW0NfbHVjMXhdXSA8LSBDX21hdHJpeF8yW1tDX2x1YzF4XV0gKyBDX21hdHJpeF8yW1tDX2x1YzR4XV0NCn0NCmZvciAoaSBpbiAxOjExKSB7DQogIEFfbHVjeDEgPSB3aGljaChuYW1lcyhBX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIDEpKQ0KICBBX2x1Y3g0ID0gd2hpY2gobmFtZXMoQV9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIGktMSwgIl8iLCA0KSkNCiAgQl9sdWN4MSA9IHdoaWNoKG5hbWVzKEJfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgMSkpDQogIEJfbHVjeDQgPSB3aGljaChuYW1lcyhCX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIDQpKQ0KICBDX2x1Y3gxID0gd2hpY2gobmFtZXMoQ19tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIGktMSwgIl8iLCAxKSkNCiAgQ19sdWN4NCA9IHdoaWNoKG5hbWVzKENfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgNCkpDQogIEFfbWF0cml4XzJbW0FfbHVjeDFdXSA8LSBBX21hdHJpeF8yW1tBX2x1Y3gxXV0gKyBBX21hdHJpeF8yW1tBX2x1Y3g0XV0NCiAgQl9tYXRyaXhfMltbQl9sdWN4MV1dIDwtIEJfbWF0cml4XzJbW0JfbHVjeDFdXSArIEJfbWF0cml4XzJbW0JfbHVjeDRdXQ0KICBDX21hdHJpeF8yW1tDX2x1Y3gxXV0gPC0gQ19tYXRyaXhfMltbQ19sdWN4MV1dICsgQ19tYXRyaXhfMltbQ19sdWN4NF1dDQp9DQpmb3IgKGkgaW4gMToxMSkgew0KICBBX2x1Y3h4ID0gd2hpY2gobmFtZXMoQV9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIGktMSwgIl8iLCBpLTEpKQ0KICBCX2x1Y3h4ID0gd2hpY2gobmFtZXMoQl9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIGktMSwgIl8iLCBpLTEpKQ0KICBDX2x1Y3h4ID0gd2hpY2gobmFtZXMoQ19tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIGktMSwgIl8iLCBpLTEpKQ0KICBBX21hdHJpeF8yW1tBX2x1Y3h4XV0gPSAwDQogIEJfbWF0cml4XzJbW0JfbHVjeHhdXSA9IDANCiAgQ19tYXRyaXhfMltbQ19sdWN4eF1dID0gMA0KfQ0KDQpBX21hdHJpeF8yIDwtIEFfbWF0cml4XzIgJT4lIHNlbGVjdCgtYyhsdWNfNF8wLCBsdWNfNF8xLCBsdWNfNF8yLCBsdWNfNF8zLCBsdWNfNF80LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfNF81LCBsdWNfNF82LCBsdWNfNF83LCBsdWNfNF84LCBsdWNfNF85LCBsdWNfNF8xMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfMF80LCBsdWNfMV80LCBsdWNfMl80LCBsdWNfM180LCBsdWNfNF80LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y181XzQsIGx1Y182XzQsIGx1Y183XzQsIGx1Y184XzQsIGx1Y185XzQsIGx1Y18xMF80KSkNCkJfbWF0cml4XzIgPC0gQl9tYXRyaXhfMiAlPiUgc2VsZWN0KC1jKGx1Y180XzAsIGx1Y180XzEsIGx1Y180XzIsIGx1Y180XzMsIGx1Y180XzQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y180XzUsIGx1Y180XzYsIGx1Y180XzcsIGx1Y180XzgsIGx1Y180XzksIGx1Y180XzEwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y18wXzQsIGx1Y18xXzQsIGx1Y18yXzQsIGx1Y18zXzQsIGx1Y180XzQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzVfNCwgbHVjXzZfNCwgbHVjXzdfNCwgbHVjXzhfNCwgbHVjXzlfNCwgbHVjXzEwXzQpKQ0KQ19tYXRyaXhfMiA8LSBDX21hdHJpeF8yICU+JSBzZWxlY3QoLWMobHVjXzRfMCwgbHVjXzRfMSwgbHVjXzRfMiwgbHVjXzRfMywgbHVjXzRfNCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzRfNSwgbHVjXzRfNiwgbHVjXzRfNywgbHVjXzRfOCwgbHVjXzRfOSwgbHVjXzRfMTAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzBfNCwgbHVjXzFfNCwgbHVjXzJfNCwgbHVjXzNfNCwgbHVjXzRfNCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfNV80LCBsdWNfNl80LCBsdWNfN180LCBsdWNfOF80LCBsdWNfOV80LCBsdWNfMTBfNCkpDQpgYGANCg0KIyAyLiBtYWtlIEFCQyBjb2wgbmFtZXMgY29uc2lzdGVudCBmb3IgdGhlIGVhc2Ugb2YgbGF0ZXIgd29yaw0KYGBge3J9DQpjb2xuYW1lcyhBX21hdHJpeF8yKVsyXSA9ICJTSCINCkFfbWF0cml4XzIgPC0gQV9tYXRyaXhfMiAlPiUNCiAgc2VsZWN0KC1jKC4uLjEpKSAlPiUgDQogIGFkZF9jb2x1bW4odXNlcl9uYW1lID0gIk5BIiwgLmJlZm9yZSA9ICJsdWNfMF8wIikgJT4lDQogIGFkZF9jb2x1bW4oc3VibWlzc2lvbiA9ICJOQSIsLmJlZm9yZSA9ICJsdWNfMF8wIikgJT4lDQogIGFkZF9jb2x1bW4oaW5kZXggPSAxOm5yb3coQV9tYXRyaXgpLCAuYmVmb3JlID0gIlNIIikNCmBgYA0KDQpgYGB7cn0NCmNvbG5hbWVzKEJfbWF0cml4XzIpWzJdID0gIlNIIg0KQl9tYXRyaXhfMiA8LSBCX21hdHJpeF8yICU+JQ0KICBzZWxlY3QoLWMoLi4uMSkpICU+JSANCiAgYWRkX2NvbHVtbih1c2VyX25hbWUgPSAiTkEiLCAuYmVmb3JlID0gImx1Y18wXzAiKSAlPiUNCiAgYWRkX2NvbHVtbihzdWJtaXNzaW9uID0gIk5BIiwuYmVmb3JlID0gImx1Y18wXzAiKSAlPiUNCiAgYWRkX2NvbHVtbihpbmRleCA9IDE6bnJvdyhCX21hdHJpeCksIC5iZWZvcmUgPSAiU0giKQ0KYGBgDQoNCmBgYHtyfQ0KQ19tYXRyaXhfMiA8LSBDX21hdHJpeF8yICU+JQ0KICBhZGRfY29sdW1uKGluZGV4ID0gMTpucm93KENfbWF0cml4XzIpLCAuYmVmb3JlID0gInVzZXJfbmFtZSIpICU+JQ0KICBhZGRfY29sdW1uKE5hbWUgPSAiTkEiLCAuYmVmb3JlID0gInVzZXJfbmFtZSIpICU+JQ0KICBhZGRfY29sdW1uKFNhdGlzZnkgPSAiTkEiLC5iZWZvcmUgPSAidXNlcl9uYW1lIikgJT4lDQogIGFkZF9jb2x1bW4oTiA9ICJOQSIsIC5iZWZvcmUgPSAidXNlcl9uYW1lIikNCmBgYA0KDQojIDMucnVuIE9OQQ0KY2FsbCBnZW5lcmF0ZS5vbmEub2JqZWN0IGZ1bmN0aW9uDQpgYGB7ciBnZW5lcmF0ZS5vbmEub2JqZWN0fQ0KZ2VuZXJhdGUub25hLm9iamVjdCA8LSBmdW5jdGlvbihkYXRhLCB1bml0LmNvbCwgbWV0YS5jb2wsIGNvZGVzKXsNCiAgb3V0cHV0IDwtIGxpc3QoKQ0KICBmLnVuaXRzIDwtIHVuaXQuY29sDQogIEVOQV9VTklUIDwtIHJFTkE6Om1lcmdlX2NvbHVtbnNfYyhmLnVuaXRzLCBjb2xzID0gY29sbmFtZXMoZi51bml0cykpOw0KICAjIEVOQV9VTklUIDwtICBmLnVuaXRzDQogIGYucmF3IDwtIGRhdGENCiAgZi5jb2RlcyA8LSBjb2Rlcw0KICBkZW5hX2RhdGEgPSBkaXJlY3RlZEVOQTo6OmVuYS5zZXQuZGlyZWN0ZWQoZi5yYXcsIGYudW5pdHMsIE5BLCBmLmNvZGVzKQ0KICBvdXRwdXQubWV0YS5kYXRhIDwtIG1ldGEuY29sDQogIGRlbmFfZGF0YSRtZXRhLmRhdGEgPC0gZGF0YS50YWJsZTo6YXMuZGF0YS50YWJsZShjYmluZChFTkFfVU5JVCwgb3V0cHV0Lm1ldGEuZGF0YSkpDQogIGZvciggaSBpbiBjb2xuYW1lcyhkZW5hX2RhdGEkbWV0YS5kYXRhKSApIHsNCiAgICBzZXQoZGVuYV9kYXRhJG1ldGEuZGF0YSwgaiA9IGksIHZhbHVlID0gckVOQTo6YXMuZW5hLm1ldGFkYXRhKGRlbmFfZGF0YSRtZXRhLmRhdGFbW2ldXSkpDQogIH0NCiAgY29kZV9sZW5ndGggPC0gbGVuZ3RoKGRlbmFfZGF0YSRyb3RhdGlvbiRjb2Rlcyk7DQogIGRlbmFfZGF0YSRyb3RhdGlvbiRhZGphY2VuY3kua2V5IDwtIGRhdGEudGFibGU6OmRhdGEudGFibGUobWF0cml4KGMoDQogICAgcmVwKDE6Y29kZV9sZW5ndGgsIGNvZGVfbGVuZ3RoKSwNCiAgICByZXAoMTpjb2RlX2xlbmd0aCwgZWFjaCA9IGNvZGVfbGVuZ3RoKSksDQogICAgYnlyb3cgPSBUUlVFLCBucm93ID0gMg0KICApKQ0KICBkaXJlY3RlZC5hZGphY2VuY3kudmVjdG9ycyA8LSBhcy5lbmEubWF0cml4KGRhdGEudGFibGU6OmFzLmRhdGEudGFibGUoZGF0YVssIGdyZXAoIlYiLCBjb2xuYW1lcyhkYXRhKSldKSwgImVuYS5jb25uZWN0aW9ucyIpDQogICMgYXJlbid0IHRoZXNlIHR3byB0aGUgc2FtZSB0aGluZyANCiAgZGVuYV9kYXRhJGNvbm5lY3Rpb24uY291bnRzIDwtIGRhdGEudGFibGU6OmFzLmRhdGEudGFibGUoY2JpbmQoZGVuYV9kYXRhJG1ldGEuZGF0YSwgZGlyZWN0ZWQuYWRqYWNlbmN5LnZlY3RvcnMpKQ0KICBkZW5hX2RhdGEkY29ubmVjdGlvbi5jb3VudHMgPSByRU5BOjphcy5lbmEubWF0cml4KHggPSBkZW5hX2RhdGEkY29ubmVjdGlvbi5jb3VudHMsICJlbmEuY29ubmVjdGlvbnMiKQ0KICBmb3IgKGkgaW4gd2hpY2goIXJFTkE6OmZpbmRfbWV0YV9jb2xzKGRlbmFfZGF0YSRjb25uZWN0aW9uLmNvdW50cykpKQ0KICAgIHNldChkZW5hX2RhdGEkY29ubmVjdGlvbi5jb3VudHMsIGogPSBpLCB2YWx1ZSA9IGFzLmVuYS5jby5vY2N1cnJlbmNlKGFzLmRvdWJsZShkZW5hX2RhdGEkY29ubmVjdGlvbi5jb3VudHNbW2ldXSkpKQ0KICBkZW5hX2RhdGEkbW9kZWwkcm93LmNvbm5lY3Rpb24uY291bnRzID0gZGF0YS50YWJsZTo6YXMuZGF0YS50YWJsZShjYmluZChkZW5hX2RhdGEkbWV0YS5kYXRhLCBkaXJlY3RlZC5hZGphY2VuY3kudmVjdG9ycykpDQogIGRlbmFfZGF0YSRtb2RlbCRyb3cuY29ubmVjdGlvbi5jb3VudHMgPC0gckVOQTo6YXMuZW5hLm1hdHJpeChkZW5hX2RhdGEkbW9kZWwkcm93LmNvbm5lY3Rpb24uY291bnRzLCAicm93LmNvbm5lY3Rpb25zIikNCiAgb3V0cHV0ID0gZGVuYV9kYXRhOw0KICByZXR1cm4ob3V0cHV0KQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KIyAxLiBwcmVwYXJlIGRmDQoNCiMgZGYgPC0gQV9tYXRyaXgNCiMgZGYgPC0gQl9tYXRyaXgNCmRmIDwtIENfbWF0cml4XzINCg0KbmFtZXMoZGYpWzc6MTA2XSA8LSBwYXN0ZTAoIlYiLHNlcSgxOjEwMCkpDQpkZiRtYXBpZCA9IG1hcGlkDQoNCiMgMi4gYWNjdW0NCmFjY3VtQyA8LSBnZW5lcmF0ZS5vbmEub2JqZWN0KA0KICBkZiwNCiAgdW5pdC5jb2wgPSBkZlssMTo3XSwNCiAgbWV0YS5jb2wgPSBkZlssMTo3XSwNCiAgY29kZXMgPSBhcy52ZWN0b3IoDQogICAgYygiQ29tbWVyY2lhbCIsDQogICAgIkNvbnNlcnZhdGlvbl9sdSIsDQogICAgIyAiQ29uc2VydmF0aW9uIiwNCiAgICAiQ3JvcGxhbmQiLA0KICAgICJJbmR1c3RyaWFsIiwNCiAgICAjICJMaW1pdGVkIFVzZSIsDQogICAgIlBhc3R1cmUiLA0KICAgICJSZWNyZWF0aW9uIiwNCiAgICAiUmVzaWRlbnRpYWwgSEQiLA0KICAgICJSZXNpZGVudGlhbCBMRCIsDQogICAgIlRpbWJlciIsDQogICAgIldldGxhbmRzIikpKQ0KDQojIDMuIG1vZGVsDQpzZXRDIDwtIG1vZGVsKGFjY3VtQykNCg0KIyA0LiBHb0YNCmNvcnJlbGF0aW9ucyhzZXRDKQ0KDQpgYGANCg0KYGBge3J9DQojIDEuIHByZXBhcmUgZGYNCg0KZGYxIDwtIEFfbWF0cml4XzINCiMgZGYgPC0gQl9tYXRyaXgNCiMgZGYgPC0gQ19tYXRyaXgNCg0KbmFtZXMoZGYxKVs3OjEwNl0gPC0gcGFzdGUwKCJWIixzZXEoMToxMDApKQ0KZGYxJG1hcGlkID0gbWFwaWQNCg0KIyAyLiBhY2N1bQ0KYWNjdW1BIDwtIGdlbmVyYXRlLm9uYS5vYmplY3QoDQogIGRmMSwNCiAgdW5pdC5jb2wgPSBkZjFbLDE6N10sDQogIG1ldGEuY29sID0gZGYxWywxOjddLA0KICBjb2RlcyA9IGFzLnZlY3RvcigNCiAgICBjKCJDb21tZXJjaWFsIiwNCiAgICAiQ29uc2VydmF0aW9uX2x1IiwNCiAgICAjICJDb25zZXJ2YXRpb24iLA0KICAgICJDcm9wbGFuZCIsDQogICAgIkluZHVzdHJpYWwiLA0KICAgICMgIkxpbWl0ZWQgVXNlIiwNCiAgICAiUGFzdHVyZSIsDQogICAgIlJlY3JlYXRpb24iLA0KICAgICJSZXNpZGVudGlhbCBIRCIsDQogICAgIlJlc2lkZW50aWFsIExEIiwNCiAgICAiVGltYmVyIiwNCiAgICAiV2V0bGFuZHMiKSkpDQoNCiMgMy4gbW9kZWwNCnNldEEgPC0gbW9kZWwoYWNjdW1BKQ0KDQojIDQuIEdvRg0KY29ycmVsYXRpb25zKHNldEEpDQpgYGANCg0KIyA0LiBwcm9qZWN0IEMgcG9pbnRzIGludG8gQSBzcGFjZQ0KVG8gZG8gc28sIEkgbmVlZCB0byBtYWtlIGEgc2V0IHVzaW5nIEMncyBhY2N1bXVsYXRpb24gYW5kIEEncyByb3RhdGlvbiBtYXRyaXgNCmBgYHtyfQ0Kc2V0PW1vZGVsKGFjY3VtQywgcm90YXRpb24uc2V0ID0gc2V0QSRyb3RhdGlvbikNCmBgYA0KDQojIDUuIG9uYSBwbG90dGluZyANCiMjIDUuMSBzZXR0aW5nIGdsb2JhbCB2aXN1YWwgcGFyYW1ldGVycyBoZXJlIHNvIHRoYXQgYWxsIE9OQSBwbG90cyB3ZSBnZW5lcmF0ZSBhcmUgb24gdGhlIHNhbWUgc2NhbGUNCmBgYHtyfQ0Kbm9kZV9zaXplX211bHRpcGxpZXIgPSAwLjINCm5vZGVfcG9zaXRpb25fbXVsdGlwbGllciA9IDEuMA0KZWRnZV9zaXplX211bHRpcGxpZXIgPSAwLjINCnBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIgPSAxLjANCmVkZ2VfYXJyb3dfc2F0dXJhdGlvbl9tdWx0aXBsaWVyID0gMS4wDQpgYGANCg0KYGBge3J9DQpvbmE6OjpwbG90LmVuYS5kaXJlY3RlZC5zZXQoc2V0QykgJT4lIA0KICB1bml0cyggDQogICAgcG9pbnRzID0gc2V0QyRwb2ludHMsDQogICAgcG9pbnRzX2NvbG9yID0gImJsYWNrIiwNCiAgICBzaG93X21lYW4gPSBGQUxTRSwgc2hvd19wb2ludHMgPSBUUlVFLCB3aXRoX2NpID0gRkFMU0UpDQpgYGANCg0KIyMgNS4yIHF1aWNrIGNoZWNrIHBvaW50cyBBUkUgYmVpbmcgcm90YXRlZA0KYGBge3J9DQpvbmE6OjpwbG90LmVuYS5kaXJlY3RlZC5zZXQoc2V0QSwgdGl0bGUgPSAic3BhY2UgdXNlZCBmb3IgcHJvamVjdGlvbiBhbmQgaXRzIHBvaW50cyIpICU+JQ0KICB1bml0cygNCiAgICBwb2ludHMgPSBzZXRBJHBvaW50cywNCiAgICBwb2ludHNfY29sb3IgPSAiZ3JheSIsDQogICAgc2hvd19tZWFuID0gVFJVRSwgc2hvd19wb2ludHMgPSBUUlVFLCB3aXRoX2NpID0gRkFMU0UpICU+JQ0KIG5vZGVzKA0KICAgIG5vZGVfc2l6ZV9tdWx0aXBsaWVyID0gMC4wMDEpIA0KDQpvbmE6OjpwbG90LmVuYS5kaXJlY3RlZC5zZXQoc2V0QywgdGl0bGUgPSAicG9pbnRzIG5lZWQgdG8gYmUgcHJvamVjdGVkIGluIGl0cyBvcmlnaW5hbCBzcGFjZSIpICU+JQ0KICB1bml0cyggDQogICAgcG9pbnRzID0gc2V0QyRwb2ludHMsDQogICAgcG9pbnRzX2NvbG9yID0gImJsYWNrIiwNCiAgICBzaG93X21lYW4gPSBGQUxTRSwgc2hvd19wb2ludHMgPSBUUlVFLCB3aXRoX2NpID0gRkFMU0UpJT4lDQogbm9kZXMoDQogICAgbm9kZV9zaXplX211bHRpcGxpZXIgPSAwLjAwMSkgDQoNCm9uYTo6OnBsb3QuZW5hLmRpcmVjdGVkLnNldChzZXQsIHRpdGxlID0gInByb2plY3RlZCBwb2ludHMgaW4gaXRzIG5ldyBzcGFjZSIpICU+JQ0KICB1bml0cygNCiAgICBwb2ludHMgPSBzZXQkcG9pbnRzLA0KICAgIHBvaW50c19jb2xvciA9ICJibGFjayIsDQogICAgc2hvd19tZWFuID0gRkFMU0UsIHNob3dfcG9pbnRzID0gVFJVRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUNCiAgdW5pdHMoDQogICAgcG9pbnRzID0gc2V0QSRwb2ludHMsDQogICAgcG9pbnRzX2NvbG9yID0gImdyYXkiLA0KICAgIHNob3dfbWVhbiA9IEZBTFNFLCBzaG93X3BvaW50cyA9IFRSVUUsIHdpdGhfY2kgPSBGQUxTRSkgJT4lDQogbm9kZXMoDQogICAgbm9kZV9zaXplX211bHRpcGxpZXIgPSAwLjAwMSkgDQpgYGANCg0KIyMgQ2x1c3RlciBDaGVjazoNCg0KDQpgYGB7cn0NCm9uYTo6OnBsb3QuZW5hLmRpcmVjdGVkLnNldChzZXRBLCB0aXRsZSA9ICJzcGFjZSB1c2VkIGZvciBwcm9qZWN0aW9uIGFuZCBpdHMgcG9pbnRzIikgJT4lDQogIHVuaXRzKA0KICAgIHBvaW50cyA9IHNldEEkcG9pbnRzLA0KICAgIHBvaW50c19jb2xvciA9ICJncmF5IiwNCiAgICBzaG93X21lYW4gPSBUUlVFLCBzaG93X3BvaW50cyA9IFRSVUUsIHdpdGhfY2kgPSBGQUxTRSkgJT4lDQogbm9kZXMoDQogICAgbm9kZV9zaXplX211bHRpcGxpZXIgPSAwLjAwMSkgDQpgYGANCg0KYGBge3J9DQpBID0gc2V0QSRwb2ludHNbRU5BX0RJUkVDVElPTj09ICdyZXNwb25zZSddDQpgYGANCg0KIyMgNS4zIFlFUyA5IG1lYW5zICsgc3VibWlzc2lvbiB0cmFqZWN0b3J5DQoNCmBgYHtyfQ0KdXNlcl9uYW1lcyA8LSB1bmlxdWUoQ19tYXRyaXgkdXNlcl9uYW1lKQ0KbiA8LSBsZW5ndGgodXNlcl9uYW1lcykNCmNvbG9yc19zZWxlY3RlZCA8LSBkaXN0aW5jdENvbG9yUGFsZXR0ZShuKQ0KcGllKHJlcCgxLG4pLCBjb2w9Y29sb3JzX3NlbGVjdGVkKQ0KYGBgDQoNCmBgYHtyfQ0Kb25hX3Bsb3QgPC0gZnVuY3Rpb24oaW5jbHVkZVN1YiA9IFRSVUUpew0KICBjb2xvcnMgPC0gYygiZ3JlZW4iLCAiYmx1ZSIsICJicm93biIsICJwdXJwbGUiLCAieWVsbG93IiwgImRlZXBwaW5rIiwgIlRhbiIsICJDeWFuIiwgIm9yYW5nZSIpDQoNCiAgcCA8LSBvbmE6OjpwbG90LmVuYS5kaXJlY3RlZC5zZXQoc2V0KSAlPiUNCiAgICB1bml0cygNCiAgICAgIHBvaW50cyA9IHNldCRwb2ludHMsDQogICAgICBwb2ludHNfY29sb3IgPSAid2hpdGUiLA0KICAgICAgcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciA9IHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIsDQogICAgICBzaG93X21lYW4gPSBGQUxTRSwNCiAgICAgIHNob3dfcG9pbnRzID0gVFJVRSwNCiAgICAgIHdpdGhfY2kgPSBGQUxTRQ0KICAgICkNCiAgDQogIGZvciAoaSBpbiAxOmxlbmd0aChzaF9uYW1lKSkgew0KICAgIHRyeUNhdGNoKHsNCiAgICAgIHAgPC0gcCAlPiUNCiAgICAgICAgdW5pdHMoDQogICAgICAgICAgcG9pbnRzID0gc2V0QSRwb2ludHNbU0ggPT0gc2hfbmFtZVtpXSAmIFNhdGlzZnkgPT0gIlllcyJdLA0KICAgICAgICAgIHBvaW50c19jb2xvciA9IGNvbG9yc1tpXSwNCiAgICAgICAgICBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyID0gcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciwNCiAgICAgICAgICBzaG93X21lYW4gPSBUUlVFLA0KICAgICAgICAgIHNob3dfcG9pbnRzID0gRkFMU0UsDQogICAgICAgICAgd2l0aF9jaSA9IFRSVUUNCiAgICAgICAgKQ0KICAgIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgew0KICAgICAgY2F0KCJBbiBlcnJvciBvY2N1cnJlZDoiLCBjb25kaXRpb25NZXNzYWdlKGUpLCAiXG4iKQ0KICAgICAgIyBJZiBhbiBlcnJvciBvY2N1cnMsIHNldCB3aXRoX2NpID0gRkFMU0UNCiAgICAgIHAgPC0gcCAlPiUNCiAgICAgICAgdW5pdHMoDQogICAgICAgICAgcG9pbnRzID0gc2V0QSRwb2ludHNbU0ggPT0gc2hfbmFtZVtpXSAmIFNhdGlzZnkgPT0gIlllcyJdLA0KICAgICAgICAgIHBvaW50c19jb2xvciA9IGNvbG9yc1tpXSwNCiAgICAgICAgICBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyID0gcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciwNCiAgICAgICAgICBzaG93X21lYW4gPSBUUlVFLA0KICAgICAgICAgIHNob3dfcG9pbnRzID0gRkFMU0UsDQogICAgICAgICAgd2l0aF9jaSA9IEZBTFNFDQogICAgICApDQogICAgfSkNCiAgfQ0KICANCiAgcCA8LSBwICU+JQ0KICAgIG5vZGVzKA0KICAgICAgbm9kZV9zaXplX211bHRpcGxpZXIgPSAwLjAxLA0KICAgICAgbm9kZV9wb3NpdGlvbl9tdWx0aXBsaWVyID0gbm9kZV9wb3NpdGlvbl9tdWx0aXBsaWVyLA0KICAgICAgc2VsZl9jb25uZWN0aW9uX2NvbG9yID0gImJsdWUiKQ0KICBpZihpbmNsdWRlU3ViKSB7DQogICAgaiA9IDANCiAgICBrID0gMQ0KICAgIHByZXYgPSAiIg0KICAgIGZvciAoaSBpbiAxOmxlbmd0aChzdWJtaXNzaW9uX25hbWUpKSB7DQogICAgICBpZiAoc3VibWlzc2lvbl9uYW1lW2ldICE9IHByZXYpIHsNCiAgICAgICAgaiA8LSBqKzENCiAgICAgICAgcHJldiA8LSBzdWJtaXNzaW9uX25hbWVbaV0NCiAgICAgICAgayA8LSAxDQogICAgICB9DQogICAgICBwIDwtIHAgJT4lDQogICAgICAgIGFkZF9hbm5vdGF0aW9ucygNCiAgICAgICAgICB4ID0gc2V0JHBvaW50c1tFTkFfRElSRUNUSU9OID09ICJyZXNwb25zZSJdJFNWRDFbaV0sDQogICAgICAgICAgeSA9IHNldCRwb2ludHNbRU5BX0RJUkVDVElPTiA9PSAicmVzcG9uc2UiXSRTVkQyW2ldLA0KICAgICAgICAgIHRleHQgPSBwYXN0ZTAoc3Vic3RyaW5nKHN1Ym1pc3Npb25fbmFtZVtpXSwgMSwgMiksICJbIiwgaywgIl0iKSwNCiAgICAgICAgICBmb250ID0gbGlzdChjb2xvciA9IGNvbG9yc19zZWxlY3RlZFtqXSksDQogICAgICAgICAgc2hvd2Fycm93ID0gRkFMU0UNCiAgICAgICAgKQ0KICAgICAgayA8LSBrKzENCiAgICB9DQogIH0NCiAgcCA8LSBwICU+JQ0KICBwbG90bHk6OmxheW91dChzaG93bGVnZW5kID0gVFJVRSwgbGVnZW5kID0gbGlzdCh4ID0gMTAwLCB5ID0gMC45KSkgJT4lIA0KICAgICAgc3R5bGUobmFtZSA9ICJwb2ludCIsIHRyYWNlcyA9IGMoMikpICU+JSANCiAgICBzdHlsZShuYW1lID0gc2hfaW5mb1sxXSwgdHJhY2VzID0gYygzKSkgJT4lIA0KICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzJdLCB0cmFjZXMgPSBjKDQpKSAlPiUgDQogICAgc3R5bGUobmFtZSA9IHNoX2luZm9bM10sIHRyYWNlcyA9IGMoNSkpICU+JSANCiAgICBzdHlsZShuYW1lID0gc2hfaW5mb1s0XSwgdHJhY2VzID0gYyg2KSkgJT4lIA0KICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzVdLCB0cmFjZXMgPSBjKDcpKSAlPiUgDQogICAgc3R5bGUobmFtZSA9IHNoX2luZm9bNl0sIHRyYWNlcyA9IGMoOCkpICU+JSANCiAgICBzdHlsZShuYW1lID0gc2hfaW5mb1s3XSwgdHJhY2VzID0gYyg5KSkgJT4lIA0KICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzhdLCB0cmFjZXMgPSBjKDEwKSkgJT4lIA0KICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzldLCB0cmFjZXMgPSBjKDExKSkNCiAgcmV0dXJuKHApDQp9DQoNCmBgYA0KDQpgYGB7cn0NCm9uYV9wbG90KEZBTFNFKQ0Kb25hX3Bsb3QoKQ0KYGBgDQoNCg==